﻿#region Class Header
/* ========================================================================
* 【本类功能概述】
* 
* 作者：chinesedragon 
* 时间：5/4/2013 5:09:41 PM
* 文件名：FormUpgradeNew
* 版本：V1.0.1
*
* 修改时间： 
* 修改说明：
* ========================================================================
*/
#endregion


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
using System.Security.Policy;
using System.Collections;

namespace Updater
{
    public partial class FormUpgradeNew : FormBase
    {
        private readonly ReleaseList localReleaseList = null;
        private readonly ReleaseList remoteReleaseList = null;
        private readonly BackgroundWorker worker = null;
        private long downloadTotalSize = 0;
        private long downloadSize = 0;
        private readonly string tempDir = string.Empty;
        private ReleaseFile[] upgradeFiles = null;

        public FormUpgradeNew(ReleaseList local, ReleaseList remote)
        {
            InitializeComponent();

            localReleaseList = local;
            remoteReleaseList = remote;

            worker = new BackgroundWorker();
            worker.WorkerReportsProgress = true;
            worker.DoWork += worker_DoWork;
            worker.RunWorkerCompleted += worker_WorkComplete;
            worker.ProgressChanged += worker_ProgressChanged;

            tempDir = Path.GetTempPath() + localReleaseList.AppName;
            if (Directory.Exists(tempDir))
                Directory.Delete(tempDir, true);
            Directory.CreateDirectory(tempDir);
        }

        private void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            using (DownloadHelper downloader = DownloadHelperFactory.CreateInstance(localReleaseList.ReleaseUrl, localReleaseList.UserName, localReleaseList.UserPassword))
            {
                foreach (ReleaseFile file in upgradeFiles)
                {
                    try
                    {
                        downloader.DownloadFile(tempDir,
                            localReleaseList.ReleaseUrl + "\\" + remoteReleaseList.ReleaseVersion,
                            file.FileName, ref downloadSize, worker, downloadTotalSize);
                    }
                    catch
                    {
                        e.Result = file.FileName;
                        throw;
                    }
                }
            }            
        }
        private void worker_WorkComplete(object sender, RunWorkerCompletedEventArgs e)
        {
            btnNext.Enabled = true;
            if (e.Error != null)
            {
                Directory.Delete(tempDir, true);
                MessageBox.Show(e.Error.Message);
                return;
            }
            //安装新文件
            CloseProcess();
            Installer.Install(tempDir, Application.StartupPath);
            //结束安装，保存ReleaseList
            string localPath = Path.Combine(Application.StartupPath, GlobalValue.ReleaseListName);
            XmlSerializeHelper.SaveXmlFormObject(localPath, remoteReleaseList);
            GlobalValue.StartExec(remoteReleaseList.StartupExec);
            Application.Exit();
        }
        private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar1.Value = e.ProgressPercentage;
            lblSize.Text = string.Format("{0}/{1}", GlobalValue.FormatFileSize(downloadSize), 
                GlobalValue.FormatFileSize(downloadTotalSize));
        }

        private void FormUpgradeNew_Load(object sender, EventArgs e)
        {
            lblSize.Text = string.Empty;
            linkLabel1.Text = string.Empty;
            lblTitle.Text = string.Format(lblTitle.Text,
                localReleaseList.ReleaseVersion, remoteReleaseList.ReleaseVersion, remoteReleaseList.ReleaseDate);
            txtDesc.Text = remoteReleaseList.ReleaseNote;
            upgradeFiles = GetDifferentFiles(out downloadTotalSize);
            lblSize.Text = string.Format("更新文件总大小:{0}", GlobalValue.FormatFileSize(downloadTotalSize));
            if (!string.IsNullOrEmpty(remoteReleaseList.SupportUrl))
            {
                linkLabel1.Text = string.Format("更新支持:{0}", remoteReleaseList.SupportUrl);
            }
            progressBar1.Maximum = 100;
            progressBar1.Minimum = 0;
        }

        private void btnNext_Click(object sender, EventArgs e)
        {            
            if (worker.IsBusy)
            {
                return;
            }
            btnNext.Enabled = false;

            progressBar1.Value = 0;
            downloadSize = 0;

            worker.RunWorkerAsync();
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            GlobalValue.StartExec(localReleaseList.StartupExec);
            Application.Exit();
        }

        private ReleaseFile[] GetDifferentFiles(out long totalSize)
        {
            totalSize = 0;
            List<ReleaseFile> upFiles = new List<ReleaseFile>();

            Hashtable ht = new Hashtable();
            foreach (ReleaseFile file in localReleaseList.Files)
            {
                ht.Add(file.FileName.ToLower(), file.Version);
            }

            foreach (ReleaseFile file in remoteReleaseList.Files)
            {
                if ( (!ht.ContainsKey(file.FileName.ToLower())) //本地没有包含远程文件
                    || ht[file.FileName.ToLower()] == null  //本地虽包含但没有版本
                    || GlobalValue.CompareVersion(ht[file.FileName.ToLower()].ToString(),file.Version) != 0 //两者版本不一致
                    )
                {
                    upFiles.Add(file);
                    totalSize += file.FileSize;
                }
            }

            return upFiles.ToArray();
        }

        private void CloseProcess()
        {
            string processName = localReleaseList.StartupExec.Substring(0, localReleaseList.StartupExec.Length - 4);
            Process[] processes = Process.GetProcessesByName(processName);
            foreach (Process myProcess in processes)
            {
                myProcess.Kill();
            }
        }
    }
}
